/*
* Copyright © Shanghai Awinic Technology Co., Ltd. 2020-2020. All rights reserved.
* Description: PWR driver related library function files.
* Date： 20201126
* Awinic_Version： aw_soc_driver_v1.0.0
*/
#include "compile_option.h"
#ifdef AW_86802

#include "aw8680x_global.h"

/**
  * @brief  aw delay function
  * @param  delay_num
  * @retval None
  */
static void aw_pwr_delay(AW_U8 delay_num)
{
	AW_U32 i = AW_NUM_NULL;
	AW_U32 j = AW_NUM_NULL;

	for (j = AW_NUM_NULL; j < delay_num; j++) {
		for (i = AW_NUM_NULL; i < DELAY_ONE_TIME; i++) {
			__NOP();
		}
	}
}

/**
  * @brief  PWR interrupt number configuration function
  * @param  pwr_irq_pri_e is used to set interrupt priority
  * @retval None
  */
static void pwr_irq_config(IRQ_PRI_E pwr_irq_pri_e)
{
	NVIC_EnableIRQ(IRQ_SWDT); // Enable Interrupt.
	NVIC_SetPriority(IRQ_SWDT, pwr_irq_pri_e); // Set Interrupt Priority.
}

/**
  * @brief  PWR sleep mode configuration function
  * @param  PWR pointer to a PWR_HANDLE_TYPE_S structure that contains
  *                the configuration information for the specified PWR.
  * @retval RET_STATUS_E status
  */
static RET_STATUS_E pwr_sleep_config(PWR_HANDLE_TYPE_S *p_pwr_lib)
{
	/* Check the PWR handle allocation. */
	if (p_pwr_lib == AW_NULL) {
		return RET_ERROR;
	}

	protect_unlock();
	PWR->SLP_MOD = p_pwr_lib->init_s.pwr_mode_e; // Config mode
	PWR->SLP_EN |= AW_EN; // Enable sleep mode.
	FMC->ISP_CR |= p_pwr_lib->init_s.pwr_dp_flash; // Config flash dp mode.
	FMC->ISP_CMD = ISPCMD_DIS;
	protect_lock();

	return RET_OK;
}

/**
  * @brief  PWR power down mode configuration function
  * @param  PWR pointer to a PWR_HANDLE_TYPE_S structure that contains
  *                the configuration information for the specified PWR.
  * @retval RET_STATUS_E status
  */
static RET_STATUS_E pwr_down_config(PWR_HANDLE_TYPE_S *p_pwr_lib)
{
	/* Check the PWR handle allocation. */
	if (p_pwr_lib == AW_NULL) {
		return RET_ERROR;
	}

	protect_unlock();
	PWR->SLP_MOD = p_pwr_lib->init_s.pwr_mode_e; // Config mode
	PWR->PD_EN |= AW_EN; // Enable power down mode.
	FMC->ISP_CR |= p_pwr_lib->init_s.pwr_dp_flash; // Config flash dp mode.
	FMC->ISP_CMD = ISPCMD_DIS;
	protect_lock();

	return RET_OK;
}

/**
  * @brief  Write load value function
  * @param  pwr_load_cent
  * @retval None
  */
void pwr_swdt_load_fun(AW_U32 pwr_load_cent)
{
	protect_unlock();
	PWR->SLP_DLY = SLP_DELAY_NUM;
	/* Config sleep Wake-up time. */
	/* SWDT macro definition */
	/* SWdt_delay = pwr_load_cent * 16 * 25us    LOSC = 40K*/
	/* SWdt_delay = pwr_load_cent * 400us */
	/* SWdt_delay = pwr_load_cent * 16 * 28.5us  LOSC = 35K*/
	/* SWdt_delay = pwr_load_cent * 456us */
	/* SWdt_delay = pwr_load_cent * 16 * 33us    LOSC = 30K*/
	/* SWdt_delay = pwr_load_cent * 528us */
	// pwr_load_cent = 10ms  0x14 40ms 0x50 2000ms 0xFFC
	PWR->SWDT_LOAD_CNT = LOAD_CENT_CLEN;
	PWR->SWDT_LOAD_CNT |= (pwr_load_cent << PWR_LOAD_CENT_OFFSET);
	PWR->SWDT_LOAD_CNT |= PWR_DELAY_TIME;

	/* Make configuration time valid. */
	PWR->SWDT_LOAD_EN |= AW_EN;
	aw_pwr_delay(PWR_DELAY);
	PWR->SWDT_LOAD_EN = AW_DIS;
	protect_lock();
}

/**
  * @brief  PWR initialization function
  * @param  PWR pointer to a PWR_HANDLE_TYPE_S structure that contains
  *         the configuration information for the specified PWR.
  * @retval RET_STATUS_E status
  */
RET_STATUS_E pwr_init(PWR_HANDLE_TYPE_S *p_pwr_lib)
{
	/* Check the PWR handle allocation. */
	if (p_pwr_lib == AW_NULL) {
		return RET_ERROR;
	}

	assert_param(PWR_CHECK_MODE(p_pwr_lib->init_s.pwr_mode_e));

	/* Config PWR */
	pwr_irq_config(p_pwr_lib->pwr_irq_pri_e); // Config interrupt number.
	protect_unlock(); // Unlock
	PWR->SWDT_EN &= AW_DIS; // Close SWDT
	PWR->SWDT_LOAD_EN &= AW_DIS; // Close SWDT load
	protect_lock();

	if (p_pwr_lib->init_s.pwr_mode_e == SLEEP_MODE) {
		pwr_sleep_config(p_pwr_lib);
	} else if (p_pwr_lib->init_s.pwr_mode_e == DP_SLEEP) {
		pwr_sleep_config(p_pwr_lib);
	} else if (p_pwr_lib->init_s.pwr_mode_e == POWER_DOWN) {
		pwr_down_config(p_pwr_lib);
	}

	pwr_swdt_load_fun(p_pwr_lib->init_s.pwr_load_cent); // Config sleep Wake-up time

	return RET_OK;
}

/**
  * @brief  Turn on low power mode function
  * @param  pwr_load_cent
  * @retval None
  */
void pwr_slp_go(void)
{
	/* Turn on sleep mode. */
	protect_unlock(); // Unlock
	PWR->SLP_GO &= AW_DIS;
	PWR->SLP_GO |= AW_EN;
	protect_lock(); // Lock
	__DSB();
	__WFI();
}

/**
  * @brief  Clear SWDT interrupt function
  * @param  None
  * @retval None
  */
void pwr_clean_irq(void)
{
	protect_unlock();
	PWR->SWDT_INTR_CLR = SWDT_CLR;
	PWR->SWDT_INTR_CLR = ~SWDT_CLR;
	protect_lock();
}

/**
  * @brief  PWR interruption of service function
  * @param  None
  * @retval None
  */
__weak void pwr_irq(void)
{
	/* NOTE : This function Should not be modified, when the callback is needed,
			the pwr_irq_call could be implemented in the user file
	*/

	/* Clear the existing interruption. */
	pwr_clean_irq();
}
#endif
